/*
 * pps_bom
 */
package com.pitop.assembly.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baidu.fsg.uid.UidGenerator;
import com.pitop.assembly.dao.*;
import com.pitop.assembly.entity.*;
import com.pitop.bom.entity.BomDetailType;
import com.pitop.core.base.BaseDAO;
import com.pitop.core.base.BaseSVImpl;
import com.pitop.core.entity.Page;
import com.pitop.core.exceptions.AssemblyException;
import com.pitop.core.exceptions.BaseException;
import com.pitop.core.tools.StringTools;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service("assemblySV")
@Slf4j
public class AssemblySVImpl extends BaseSVImpl<Assembly, Long> implements AssemblySV {

    @Autowired
    private AssemblyDAO assemblyDAO;

    @Autowired
    private AssemblyCategoryDAO assemblyCategoryDAO;

    @Autowired
    private AssemblyMaterialDAO assemblyMaterialDAO;

    @Autowired
    private AssemblyLogDAO assemblyLogDAO;

    @Autowired
    private AssemblyImageDAO assemblyImageDAO;
    @Resource
    private UidGenerator uidGenerator;

    @Override
    protected BaseDAO getBaseDAO() {
        return assemblyDAO;
    }

    /**
     * * 创建Assembly
     * 1.参数合法性验证
     * ****1.1 参数是否为空
     * ****1.2组件名称是否已经存在，组件代码是否已经存在
     * ****1.3组件类型编码是否有效
     * ****1.4组件上级编码是否正确
     * 2.上级编码是否存在，如果不存在，设置组件级别为1级；如果存在，上级组件级别加1
     * 3.持久化组件数据
     * 4.持久化构成组件的物料表
     * 5.持久化组件日志
     * 6.图纸信息存在，持久化组件信息
     *
     * @param entity 实体
     */
    @Override
    public void save(Assembly entity, String account, String code) throws BaseException {
        //1.参数合法性验证
        //1.1 参数是否为空
        if (entity == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Empty_Param);
        }
        if (StringTools.isEmpty(entity.getCategoryCode()) || StringTools.isEmpty(entity.getName()) || StringTools.isEmpty(entity.getAssemblyCode())) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Empty_Param);
        }
        //1.2组件名称是否已经存在，组件代码是否已经存在
        Assembly assembly = assemblyDAO.loadByName(entity.getName());
        if (assembly != null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Exists);
        }
        Map<String, Object> params = new HashedMap();
        params.put("assemblyCode", entity.getAssemblyCode());
        assembly = assemblyDAO.load(params);
        if (assembly != null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Exists);
        }
        //1.3组件类型编码是否有效
        AssemblyCategory assemblyCategory = assemblyCategoryDAO.loadByCode(entity.getCategoryCode());
        if (assemblyCategory == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Result_Not_Exist);
        }
        //1.4组件上级编码是否正确
        if (StringTools.isNotEmpty(entity.getPreCode())) {
            assembly = assemblyDAO.loadByCode(entity.getPreCode());
            if (assembly == null) {
                throw new AssemblyException(BaseException.BaseExceptionEnum.Result_Not_Exist);
            }
        }
        //2.上级编码是否存在，如果不存在，设置组件级别为1级；如果存在，上级组件级别加1
        if (assembly == null) {
            entity.setLevel(1);
        } else {
            entity.setLevel(assembly.getLevel() + 1);
        }
        //3.持久化组件数据
        entity.setCode(String.valueOf(uidGenerator.getUID()));
        entity.setState(AssemblyState.Develop.name());
        entity.setCreateTime(new Date());
        entity.setUpdateTime(new Date());
        super.save(entity);

        //4.持久化构成组件的物料表
        //this.insertAssemblyMaterial(entity.getMaterialCodes(), entity.getCode());

        //5.持久化组件日志
        String summary = "管理员" + account + "创建了组件" + entity.getName();
        AssemblyLog assemblyLog = new AssemblyLog(entity.getCode(), AssemblyLogState.Modify.name(), code, account, summary);
        assemblyLogDAO.insert(assemblyLog);

        //6.图纸信息存在，持久化组件信息
        this.insertAssemblyImage(entity.getDesignFileUrls(), entity.getCode(), entity.getSummary());
    }

    /**
     * 修改组件
     * * * 1.参数合法性验证
     * ****1.1 参数是否为空
     * ****1.2 根据组件编码查询组件
     * ****1.3 组件名称是否已经存在，组件代码是否已经存在
     * ****1.4 组件类型编码是否有效
     * 2.1 组件上级编码是否正确
     * 2.2上级编码是否存在，如果不存在，设置组件级别为1级；如果存在，上级组件级别加1
     * 3.持久化组件数据：修改
     * 4.持久化构成组件的物料表，先删除再添加
     * 5.持久化组件日志
     * 6.图纸信息存在，持久化组件信息：删除重新添加
     *
     * @param assembly 组件信息
     * @param account  账号信息
     * @param code     账号编码
     */
    @Override
    public void modify(Assembly assembly, String account, String code) {
        //1.参数合法性验证
        //1.1 参数是否为空
        if (assembly == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Empty_Param);
        }
        if (StringTools.isEmpty(assembly.getCategoryCode()) || StringTools.isEmpty(assembly.getName())
                || StringTools.isEmpty(assembly.getAssemblyCode()) || StringTools.isEmpty(assembly.getCode())) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Empty_Param);
        }
        //1.2 根据组件编码查询组件
        Assembly entity = assemblyDAO.loadByCode(assembly.getCode());
        if (entity == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Result_Not_Exist);
        }
        //1.3 组件名称是否已经存在
        Assembly assemblyFlag = assemblyDAO.loadByName(assembly.getName());
        if (assemblyFlag != null && !assemblyFlag.getCode().equals(assembly.getCode())) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Assembly_Exist);
        }
        //1.4 组件类型编码是否有效
        AssemblyCategory assemblyCategory = assemblyCategoryDAO.loadByCode(entity.getCategoryCode());
        if (assemblyCategory == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Assembly_Category_Not_Exist);
        }

        //2.1 组件上级编码是否正确
        Assembly fatherAssembly = null;
        if (StringTools.isNotEmpty(entity.getPreCode())) {
            fatherAssembly = assemblyDAO.loadByCode(entity.getPreCode());
            if (fatherAssembly == null) {
                throw new AssemblyException(BaseException.BaseExceptionEnum.Assembly_Not_Exist);
            }
        }
        //2.2上级编码是否存在，如果不存在，设置组件级别为1级；如果存在，上级组件级别加1
        if (fatherAssembly == null) {
            entity.setLevel(1);
        } else {
            entity.setLevel(fatherAssembly.getLevel() + 1);
        }
        //3.持久化组件数据
        assembly.setUpdateTime(new Date());
        assemblyDAO.update(assembly);


        //5.持久化组件日志
        String summary = "管理员" + account + "修改了组件" + entity.getName() + ",修改后的名称是：" + assembly.getName();
        AssemblyLog assemblyLog = new AssemblyLog(assembly.getCode(), AssemblyLogState.Modify.name(), code, account, summary);
        assemblyLogDAO.insert(assemblyLog);

        //6.图纸信息存在，持久化组件信息：删除重新添加
        Map<String, Object> params = new HashedMap();
        params.put("assemblyCode", assembly.getCode());
        assemblyImageDAO.delete(params);
        this.insertAssemblyImage(assembly.getDesignFileUrls(), assembly.getCode(), assembly.getSummary());

    }

    /**
     * 添加组件绑定的物料信息
     *
     * @param code          组件编码
     * @param materialCodes 物料信息
     */
    @Override
    public void addMaterial(String code, String materialCodes) {
        Assembly assembly = assemblyDAO.loadByCode(code);
        if (assembly == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Result_Not_Exist);
        }
        if (StringTools.isNotEmpty(materialCodes)) {
            String[] arrays = materialCodes.split(",");
            AssemblyMaterial assemblyMaterial;
            Map<String, Object> params;
            for (String arr : arrays) {
                params = new HashedMap();
                params.put("assemblyCode", code);
                params.put("materialCode", arr);
                assemblyMaterial = assemblyMaterialDAO.load(params);
                if (assemblyMaterial != null) {
                    continue;
                }
                assemblyMaterial = new AssemblyMaterial();
                assemblyMaterial.setAssemblyCode(code);
                assemblyMaterial.setMaterialCode(arr);
                assemblyMaterialDAO.insert(assemblyMaterial);
            }
        }
    }

    /**
     * 修改状态
     * 1.参数合法性验证
     * 2.组件信息是否存在
     * 3.组件状态是否允许修改
     *
     * @param code  组件编码
     * @param state 状态
     */
    @Override
    public void updateState(String code, String state) {
        Assembly assembly = assemblyDAO.loadByCode(code);
        if (assembly == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Result_Not_Exist);
        }
        if (AssemblyState.Stop == AssemblyState.getEnum(assembly.getState())) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Assembly_State_Is_Stop);
        }
        if (AssemblyState.Stable == AssemblyState.getEnum(assembly.getState())) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Assembly_State_Is_Stable);
        }
        assembly.setState(state);
        assemblyDAO.update(assembly);
    }

    /**
     * 根据bom编码查询组件信息
     *
     * @param bomCode bom编码
     * @param name    组件名称
     * @param offset  查询开始行
     * @param limit   查询行数
     * @return List<Assembly>
     */
    @Override
    public List<Assembly> listForBom(String bomCode, String name, int offset, int limit) {
        Map<String, Object> params = new HashedMap();
        params.put("bomCode", bomCode);
        params.put("state", AssemblyState.Stop.name());
        params.put("name", name);
        params.put("type", BomDetailType.Assembly.name());
        List<Assembly> assemblies = assemblyDAO.listForBom(params, new RowBounds(offset, limit));
        return assemblies;
    }

    /**
     * 根据bom编码统计组件信息
     *
     * @param bomCode bom编码
     * @param name    组件名称
     * @return int
     */

    @Override
    public int countForBom(String bomCode, String name) {
        Map<String, Object> params = new HashedMap();
        params.put("bomCode", bomCode);
        params.put("state", AssemblyState.Stop.name());
        params.put("name", name);
        params.put("type", BomDetailType.Assembly.name());
        return assemblyDAO.countForBom(params);
    }

    /**
     * 复制组件
     * 1.复制组件，修改编码，组件名称为：原组件名称+复制
     * 2.复制组件图库，修改组件编码
     * 3.复制组件物料信息
     * 4.添加组件日志，日志类型为copy
     *
     * @param code        组件编码
     * @param account     管理员信息
     * @param accountCode 管理员编码
     */
    @Override
    public void copy(String code, String account, String accountCode) {
        Assembly assembly = assemblyDAO.getByCode(code);
        if (assembly == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Result_Not_Exist);
        }
        //1.复制组件，修改编码，组件名称为：原组件名称+复制
        Assembly copyAssembly = assembly;
        copyAssembly.setCode(String.valueOf(uidGenerator.getUID()));
        copyAssembly.setName(assembly.getName() + "_copy");
        if (StringTools.isNotEmpty(assembly.getAssemblyCode())) {
            copyAssembly.setAssemblyCode(assembly.getAssemblyCode() + "_copy");
        }
        copyAssembly.setState(AssemblyState.Develop.name());
        copyAssembly.setId(null);
        copyAssembly.setCreateTime(new Date());
        copyAssembly.setUpdateTime(new Date());
        assemblyDAO.insert(copyAssembly);

        //2.复制组件图库，修改组件编码
        List<AssemblyImage> assemblyImages = assembly.getAssemblyImageList();
        if (assemblyImages.size() > 0) {
            for (AssemblyImage assemblyImage : assemblyImages) {
                assemblyImage.setId(null);
                assemblyImage.setAssemblyCode(copyAssembly.getCode());
                assemblyImageDAO.insert(assemblyImage);
            }
        }

        //3.复制组件物料信息
        List<AssemblyMaterial> assemblyMaterials = assembly.getAssemblyMaterialList();
        if (assemblyMaterials.size() > 0) {
            for (AssemblyMaterial assemblyMaterial : assemblyMaterials) {
                assemblyMaterial.setId(null);
                assemblyMaterial.setAssemblyCode(copyAssembly.getCode());
                assemblyMaterialDAO.insert(assemblyMaterial);
            }
        }

        //4.添加组件日志，日志类型为copy
        String summery = "管理员" + account + "复制了组件:" + assembly.getName() + ";复制后组件：" + copyAssembly.getName();
        AssemblyLog assemblyLog = new AssemblyLog(copyAssembly.getCode(), AssemblyLogState.Copy.name(), account, accountCode, summery);
        assemblyLogDAO.insert(assemblyLog);


    }


    /**
     * 插入组件图纸
     *
     * @param designFileUrls 图纸url
     * @param assemblyCode   组件编码
     * @param summary        描述信息
     */
    private void insertAssemblyImage(String designFileUrls, String assemblyCode, String summary) {
        if (StringTools.isNotEmpty(designFileUrls)) {
            String[] designUrls = designFileUrls.split(",");
            AssemblyImage assemblyImage;
            for (String path : designUrls) {
                assemblyImage = new AssemblyImage();
                assemblyImage.setAssemblyCode(assemblyCode);
                assemblyImage.setCode(String.valueOf(uidGenerator.getUID()));
                assemblyImage.setPath(path);
                assemblyImage.setSummary(summary);
                assemblyImageDAO.insert(assemblyImage);
            }
        }
    }

    /**
     * 加载一个对象Assembly
     *
     * @param id
     * @param code 编码
     * @return Assembly
     */
    @Override
    public Assembly load(Long id, String code) {
        if (id == null && code == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }

        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        param.put("code", code);
        return assemblyDAO.load(param);
    }

    /**
     * 加载一个对象Assembly,(将查询关联数据)
     *
     * @param id
     * @param code 编码
     * @return Assembly
     */
    @Override
    public Assembly get(Long id, String code) {
        if (id == null && code == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }

        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        param.put("code", code);
        return assemblyDAO.getDetail(id, code);
    }

    /**
     * 加载一个对象Assembly 通过id
     *
     * @param id
     * @return Assembly
     */
    @Override
    public Assembly loadById(Long id) {
        if (id == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        return assemblyDAO.loadById(id);
    }

    /**
     * 加载一个对象Assembly 通过code
     *
     * @param code 编码
     * @return Assembly
     */
    @Override
    public Assembly loadByCode(String code) {
        if (code == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        return assemblyDAO.loadByCode(code);
    }

    /**
     * 加载一个对象Assembly 通过name
     *
     * @param name 名称
     * @return Assembly
     */
    @Override
    public Assembly loadByName(String name) {
        return assemblyDAO.loadByName(name);
    }

    /**
     * 加载一个对象Assembly 通过assemblyCode
     *
     * @param assemblyCode 组件代码
     * @return Assembly
     */
    @Override
    public Assembly loadByAssemblyCode(String assemblyCode) {
        return assemblyDAO.loadByAssemblyCode(assemblyCode);
    }

    /**
     * 加载一个对象Assembly 通过id,(将查询关联数据)
     *
     * @param id
     * @return Assembly
     */
    @Override
    public Assembly getById(Long id) {
        if (id == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        return assemblyDAO.getById(id);
    }

    /**
     * 加载一个对象Assembly 通过code,(将查询关联数据)
     *
     * @param code 编码
     * @return Assembly
     */
    @Override
    public Assembly getByCode(String code) {
        if (code == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        Assembly assembly = assemblyDAO.getByCode(code);
        if (assembly != null && StringTools.isNotEmpty(assembly.getPreCode())) {
            assembly.setPreName(assemblyDAO.loadByCode(assembly.getPreCode()).getName());
        }
        return assembly;
    }

    /**
     * 根据主键id,oldStates 共同更新 Assembly 的状态到newState状态
     *
     * @param id
     * @param newState  新状态
     * @param oldStates 旧状态集合
     */
    @Override
    public void updateStateById(Long id, AssemblyState newState, AssemblyState... oldStates) {
        if (id == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (newState == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (oldStates == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        String[] states = new String[oldStates.length];
        for (int i = 0; i < oldStates.length; i++) {
            states[i] = oldStates[i].name();
        }
        assemblyDAO.updateStateById(id, new Date(), newState.name(), states);
    }

    /**
     * 根据主键code,oldStates 共同更新 Assembly 的状态到newState状态
     *
     * @param code      编码
     * @param newState  新状态
     * @param oldStates 旧状态集合
     */
    @Override
    public void updateStateByCode(String code, AssemblyState newState, AssemblyState... oldStates) {
        if (code == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (newState == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (oldStates == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        String[] states = new String[oldStates.length];
        for (int i = 0; i < oldStates.length; i++) {
            states[i] = oldStates[i].name();
        }
        assemblyDAO.updateStateByCode(code, new Date(), newState.name(), states);
    }

    /**
     * 根据主键id 更新 Assembly 的状态到另一个状态
     *
     * @param id
     * @param state 状态
     */
    @Override
    public void updateById(Long id, AssemblyState state) {
        if (id == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        assemblyDAO.updateById(id, state.name(), new Date());
    }

    /**
     * 根据主键code 更新 Assembly 的状态到另一个状态
     *
     * @param code  编码
     * @param state 状态
     */
    @Override
    public void updateByCode(String code, AssemblyState state) {
        if (code == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        assemblyDAO.updateByCode(code, state.name(), new Date());
    }


    /**
     * 删除对象Assembly
     *
     * @param id * @param code 编码
     * @return Assembly
     */
    @Override
    public void delete(Long id, String code) {
        if (id == null && code == null) {
            throw new AssemblyException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        param.put("code", code);
        assemblyDAO.delete(param);
    }


    /**
     * 查询Assembly分页
     *
     * @param assembly 对象
     * @param offset   查询开始行
     * @param limit    查询行数
     * @return List<Assembly>
     */
    @Override
    public List<Assembly> list(Assembly assembly, int offset, int limit) {
        if (offset < 0) {
            offset = 0;
        }

        if (limit < 0) {
            limit = Page.limit;
        }

        Map<String, Object> map = null;
        if (assembly != null) {
            map = JSON.parseObject(JSON.toJSONString(assembly, SerializerFeature.WriteDateUseDateFormat));
        } else {
            map = new HashMap<>();
        }
        List<Assembly> assemblyList = assemblyDAO.list(map, new RowBounds(offset, limit));
        if (assemblyList.size() > 0) {
            for (Assembly assemblyFlag : assemblyList) {
                assemblyFlag.setCategoryName(assemblyCategoryDAO.loadByCode(assemblyFlag.getCategoryCode()).getName());
                if (StringTools.isNotEmpty(assemblyFlag.getPreCode())) {
                    assemblyFlag.setPreName(assemblyDAO.loadByCode(assemblyFlag.getPreCode()).getName());
                }
            }
        }
        return assemblyList;
    }

    @Override
    public int count(Assembly assembly) {
        Map<String, Object> map = null;
        if (assembly != null) {
            map = JSON.parseObject(JSON.toJSONString(assembly, SerializerFeature.WriteDateUseDateFormat));
        } else {
            map = new HashMap<>();
        }
        return assemblyDAO.count(map);
    }

    /**
     * 查询Assembly分页
     *
     * @param id     * @param code  编码
     * @param offset 查询开始行
     * @param limit  查询行数
     * @return List<Assembly>
     */
    @Override
    public List<Assembly> list(Long id, String code, int offset, int limit) {
        if (offset < 0) {
            offset = 0;
        }

        if (limit < 0) {
            limit = Page.limit;
        }
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        param.put("code", code);
        return assemblyDAO.list(param, new RowBounds(offset, limit));
    }

    @Override
    public int count(Long id, String code) {
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        param.put("code", code);
        return assemblyDAO.count(param);
    }


}
